#ifndef LIST_C
#define LIST_C
#include<iostream>
#include<stack>
#include<math.h>
#include<cctype>//为了引入isdigit（）函数
using namespace std;

stack<char> Op;//操作符栈
stack<double> Num;//操作数栈


/*传入一个字符型变量，判断其的优先级并将优先级返回*/ 
int level(char ch)
{
	switch(ch)
	{
		case'(':
			return 0;
		
		case'-':
		case'+':
			return 1;
		
		case'*':
		case'/':
		case'%': 
			return 2;
			
		case'^':
			return 3;
			
		case'!':
			return 4;
			
		case')':
			return 5;
	}
}


/*传入一个字符串（中缀表达式），将其转变为后缀表达式并返回*/
string change(string &str1)
{
	string str2;//用于存储转变后的后缀表达式 
	int temp1 = 0;//用于判断字符是否为0~9之中的一个判断符,0为在数字外，1为在数字内。 
	int temp2 = 0;
	char c;//用于短暂储存字符串中的字符
	int num = 0;//
	
	for(int i = 0; i < str1.length(); i++)//依次读取字符串
	{
	    c = str1[i];//用于检查参数是否为十进制数，若参数为0~9则返回非0值，否则返回NULL
		if(isdigit(c))   
		{
			if(temp2 == 1)
			{
				str2 = str2 + '-';
			}
			str2 = str2 + c;//如果是数字，则直接加入到str2中 
			num *= 10;//判断其是否有十位数,百位数,千位数。。。。。。 
			num += c - '0'; //将字符转变为数字
			temp1 = 1;//表示c这个字符在数字内 
		}
		else{ 
		    if(temp1 == 0 && c == '-')
			{
			    temp2 = 1;
				continue;
			}                                
			if(temp1 == 1 && c == '.')//若当前字符为'.’,且上一个字符在数字内，则这一小串字符判断为小数
			{
				str2 = str2 + '.';//将小数点加入后缀字符串中
				num = 0;//用于多位数计算的num置0； 
				continue;//直接跳出该次循环
			 }
			if(temp1 == 1 && c != '.')//若当前字符不为'.'，且上一个字符在数字内，则判断当前字符为运算符 
			{
				str2 = str2 + ' ';//此操作是为了将后缀表达式中的每一项都分割开来以便观察 
				num = 0;
			}
			
			
			if(c == '=') 
			{
				break;
			}
			else if(c == '(')//如果当前字符为左括号，则将其直接压入操作符栈
			{
				Op.push(c); 
			}
			else if(c == ')')//如果当前字符为右括号，如果操作符栈不为空则直接将操作符栈中的元素出栈并将其加入到str2中，直到'('为止；
			{
				while(!Op.empty() && Op.top() != '(')
				{
					str2 = str2 + Op.top();
					str2 = str2 + ' ';//此操作是为了将后缀表达式中的每一项都分割开来以便观察 
				
					Op.pop();
				}
				Op.pop();//将栈顶的'('出栈，不将其加入str2中 
			}
			else
			{
				while(true)
				{
					if(Op.empty() || Op.top() == '(')//如果操作符栈是为空或者当前操作符栈顶是'('时，将当前字符直接压栈。 
				    {
					    Op.push(c);
				    }
				else if(level(c) > level(Op.top()))//如果当前字符的优先级大于操作符栈顶的优先级，则将当前字符压栈 
				{
					Op.push(c);
				}
				else//如果当前字符的优先级小于等于操作符栈顶的优先级,则将操作符栈顶元素出栈并加入str2中，直到当前字符的优先级大于操作符栈顶的优先级 
				{
					str2 = str2 + Op.top();
					str2 = str2 + ' ';//此操作是为了将后缀表达式中的每一项都分割开来以便观察 
					Op.pop();
					continue;
				 }
				break;  
				}
			}
			temp1 = 0;//表示当前字符不在数字内 
			temp2 = 0;
		}
	}
	while(!Op.empty())//当字符串读取完且操作符栈中还有剩余元素时，将剩余元素出栈并且将其加入str2中 
	{
		str2 = str2 + Op.top();
		str2 = str2 + ' ';//此操作是为了将后缀表达式中的每一项都分割开来以便观察 
		Op.pop();
	}
	
	
	return str2;

} 
double compute(string &str)
{
	int temp1 = 0;//(自定义)用于判断字符是否为0~9之中的一个判断符,0为在数字外，1为在数字内。 
	int temp2 = 0;//（自定义）用于判断后缀字符串是否包含小数 
	int temp3 = 0; 
	char c;//用于短暂储存字符串中的字符
	int num = 0;//用于读取数字 
	double count = 1.0;//用于小数的读取 
	
	for(int i = 0; i < str.length(); i++)//依次读取后缀表达式中的字符 
	{
		c = str[i];
		if(isdigit(c) || c == '.')
		{
			if(isdigit(c))
			{
				
				num *= 10;//用于读取有十位数,百位数,千位数。。。。。。
				num += c - '0';//将字符转化为数字 
				temp1 = 1;//表示当前字符为数字 
				if(temp2 == 1)//表示当前字符是小数点后的字符，有多少位小数，就进行多少次这个语句 
				{
					count *= 10.0;
				}
			}
			if(c == '.')//如果当前字符是'.',则将 temp2置1，并直接退出该次循环 
			{
				temp2 = 1;
				continue; 
			}
		 }
		 else
		 {
		 	
		 	temp2 = 0;//将temp2置0； 
		 	double result = num / count;//小数的计算 
		 	if(temp3 == 1 && temp1 ==  1)
		 	{
		 		result  = -1.0 * result;
		 		temp3 = 0;
			 }
		 	count = 1.0;//将count置为初始值;
			if (temp1 == 1)//如果上一个字符在数字内，则将其之前的字符串的运算结果压入运算数栈 
			{
				Num.push(result);
				num = 0;//将num置为初始值； 
			}
			
			if(c == '-' && temp1 == 0 && str[i-1] != ')')
		 	{
		 		temp3 = 1;
		 		continue;
			 }
			
			double x, y, z;//设计三个运算数；
			if(c != ' ')//因为在中缀转后缀时加入了空格，所以要排除当前字符是空格的情况 
			{
				if(c == '!')
				{
					y = Num.top();
					Num.pop();
					
					
				}
				
				y = Num.top();//从运算数栈中取两个元素,注意顺序（顺序会影响减法和除法），后缀表达式中靠后的元素在栈中靠前 
				Num.pop();
				x = Num.top();
				Num.pop();
				
				switch(c)
				{
					case'+':
						z = x + y;
						Num.push(z);
						break;
					
					case'-':
						z = x - y;
						Num.push(z);
						break;
						
					case'*':
					    z = x * y;
						Num.push(z);
						break;
						
					case'/':
					    z = x / y;
						Num.push(z);
						break; 
						
					case'%':
					    z = fmod(x,y);//fmod函数，返回x除以y的余数 
						Num.push(z);
						break;
					
					case'^':
						z = 1.0;
					   for(int n = 0; n < y; n++)
					   {
					   	z *= x;
						}
						Num.push(z);
						break; 
				 } 
			}
			temp1 = 0; 
	    }
    } 
	return Num.top();
}

#endif
